home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 February: Technology Seed / Mac Tech Seed Feb '97.toast / ODF Release 3 / ODFDev / ODF / OS / FWGraphx / SLRegion.cpp < prev    next >
Encoding:
Text File  |  1996-12-16  |  26.6 KB  |  945 lines  |  [TEXT/MPS ]

  1. //========================================================================================
  2. //
  3. //    File:                SLRegion.cpp
  4. //    Release Version:    $ ODF 3 $
  5. //
  6. //    Copyright:    (c) 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  7. //
  8. //========================================================================================
  9.  
  10. #include "FWErrors.h"
  11.  
  12. #include "FWOS.hpp"
  13.  
  14. #ifndef SLREGION_H
  15. #include "SLRegion.h"
  16. #endif
  17.  
  18. #ifndef FWFXMATH_H
  19. #include "FWFxMath.h"
  20. #endif
  21.  
  22. #ifndef FWRECT_H
  23. #include "FWRect.h"
  24. #endif
  25.  
  26. #ifndef FWPOINT_H
  27. #include "FWPoint.h"
  28. #endif
  29.  
  30. #ifndef SLGRGLOB_H
  31. #include "SLGrGlob.h"
  32. #endif
  33.  
  34. #ifndef PRGRUTIL_H
  35. #include "PRGrUtil.h"
  36. #endif
  37.  
  38. #ifndef FWPRIDEB_H
  39. #include "FWPriDeb.h"
  40. #endif
  41.  
  42. #ifndef FWSTRMRW_H
  43. #include "FWStrmRW.h"
  44. #endif
  45.  
  46. #ifndef FWMEMHLP_H
  47. #include "FWMemHlp.h"
  48. #endif
  49.  
  50. #ifndef FWMEMMGR_H
  51. #include "FWMemMgr.h"
  52. #endif
  53.  
  54. #ifdef FW_BUILD_MAC
  55. #pragma segment FWGraphx_Region
  56. #endif
  57.  
  58. //========================================================================================
  59. //    Local helpers
  60. //========================================================================================
  61.  
  62. #ifdef FW_BUILD_MAC
  63. static GrafPtr        PrivMacOpenRegion();
  64. static ODRgnHandle    PrivMacCloseRegion(GrafPtr svPort);
  65. #endif
  66.  
  67. #ifdef FW_BUILD_WIN
  68. static void PrivWinInsetRegionRectangle(LPPOINT lppt, int dx, int dy, const POINT& ptCenter);
  69. static void PrivWinInsetRegionRectangle(LPRECT lpRect, int dx, int dy, const POINT& ptCenter);
  70. #endif
  71.  
  72. //========================================================================================
  73. //    Region functions
  74. //========================================================================================
  75.  
  76. //----------------------------------------------------------------------------------------
  77. //    FW_CreateRectRegion
  78. //----------------------------------------------------------------------------------------
  79.  
  80. ODRgnHandle SL_API    FW_CreateRectRegion(const FW_SRect& rect)
  81. {
  82.     // No try block necessary - Do not throw
  83.     FW_CPlatformRect plfmRect = rect;
  84.     
  85. #ifdef FW_BUILD_MAC
  86.     ODRgnHandle rgn = ::FW_NewRegion();
  87.     ::RectRgn(rgn, &plfmRect);
  88.     return rgn;
  89. #endif
  90. #ifdef FW_BUILD_WIN
  91.     return ::CreateRectRgnIndirect(&plfmRect);
  92. #endif
  93. }
  94.  
  95. //----------------------------------------------------------------------------------------
  96. //    FW_CreateOvalRegion
  97. //----------------------------------------------------------------------------------------
  98.  
  99. ODRgnHandle SL_API    FW_CreateOvalRegion(const FW_SRect& rect)
  100. {
  101.     // No try block necessary - Do not throw
  102.     FW_CPlatformRect plfmRect(rect);
  103.  
  104. #ifdef FW_BUILD_MAC
  105.     GrafPtr svPort = PrivMacOpenRegion();
  106.     ::FrameOval(&plfmRect);
  107.     return PrivMacCloseRegion(svPort);
  108. #endif
  109.  
  110. #ifdef FW_BUILD_WIN
  111.     return ::CreateEllipticRgnIndirect(&plfmRect);
  112. #endif
  113. }
  114.  
  115. //----------------------------------------------------------------------------------------
  116. //    FW_CreateRoundRectRegion
  117. //----------------------------------------------------------------------------------------
  118.  
  119. ODRgnHandle SL_API    FW_CreateRoundRectRegion(const FW_SRect& rect, const FW_SPoint& ovalSize)
  120. {
  121.     // No try block necessary - Do not throw
  122.     FW_CPlatformRect plfmRect(rect);
  123.     FW_CPlatformPoint plfmPoint(ovalSize);
  124.  
  125. #ifdef FW_BUILD_MAC
  126.     GrafPtr svPort = PrivMacOpenRegion();
  127.     ::FrameRoundRect(&plfmRect, plfmPoint.X(), plfmPoint.Y());
  128.     return ::PrivMacCloseRegion(svPort);
  129. #endif
  130. #ifdef FW_BUILD_WIN
  131.     return ::CreateRoundRectRgn(plfmRect.left, plfmRect.top, 
  132.                                 plfmRect.right, plfmRect.bottom, 
  133.                                 plfmPoint.X(), plfmPoint.Y());
  134. #endif
  135. }
  136.  
  137. //----------------------------------------------------------------------------------------
  138. //    FW_CreateArcRegion
  139. //----------------------------------------------------------------------------------------
  140.  
  141. ODRgnHandle SL_API FW_CreateArcRegion(const FW_SRect& rect,
  142.                                       short startAngle, short arcAngle)
  143. {
  144.     // No try block necessary - Do not throw
  145.     // However, if a memory error occurs, we may return NULL!
  146.     
  147.     FW_CPlatformRect plfmRect(rect);
  148.  
  149.     // first, we make a polygon with the segmented arc a little outside of the tru arc
  150.     
  151.     const unsigned short enlargeFactor = 8; // magic number: we enlarge the rectangle
  152.     const short width = plfmRect.right - plfmRect.left;
  153.     const short height = plfmRect.bottom - plfmRect.top;
  154.     short outset = FW_FixedToInt(FW_Sqrt(FW_IntToFixed(width / enlargeFactor)));
  155.     
  156.     plfmRect.left -= outset;
  157.     plfmRect.right += outset;
  158.  
  159.     if(width != height)
  160.         outset = FW_FixedToInt(FW_Sqrt(FW_IntToFixed(height / enlargeFactor)));
  161.         
  162.     plfmRect.top -= outset;
  163.     plfmRect.bottom += outset;
  164.  
  165.     // normalize the starting point and arc angles for the coord system used by Quickdraw
  166.     
  167.     // any arc of >= 360 or <= -360 describes the whole circle
  168.     
  169.     if ((startAngle > 360) || (startAngle < -360))
  170.             startAngle = startAngle % 360;
  171.  
  172.     if (arcAngle > 360)
  173.         arcAngle = 360;
  174.     else
  175.     if (arcAngle < -360)
  176.         arcAngle = -360;
  177.     
  178.     // start with a new, empty region
  179.     ODRgnHandle hArcRegion = FW_NewRegion();
  180.     
  181.     if(arcAngle != 0)
  182.     {
  183.         // brp : kDegreesPerSegment could be made resolution dependent, but that might be a performance hit !!!
  184.         const unsigned short kDegreesPerSegment = 5; // one line segment for every kDegreesPerSegment degrees
  185.            const unsigned short kMaxPoints = (360 / kDegreesPerSegment) + 1; // max segments + 1
  186.         
  187.         // 360 must be evenly divisable by kDegreesPerSegment
  188.         FW_ASSERT(((360 / kDegreesPerSegment) * kDegreesPerSegment) == 360);
  189.  
  190.         unsigned short numSegments = ((arcAngle > 0 ? arcAngle : -arcAngle) + kDegreesPerSegment - 1) / kDegreesPerSegment;
  191.             
  192.         short angle = startAngle;
  193.         
  194.         FW_SPoint pt[kMaxPoints + 1]; //  (numSegments + 1) points for the arc plus one for the center
  195.         for (unsigned short i = 0; i <= numSegments; i++) // we create numSegments +1 points for the arc
  196.         {
  197.             angle = startAngle + arcAngle * i / numSegments;
  198.             
  199.             FW_CPlatformPoint tempPt;
  200.             FW_PrivCalcArcPoints(plfmRect, angle, tempPt);
  201.             pt[i].x = FW_IntToFixed(tempPt.X());
  202.             pt[i].y = FW_IntToFixed(tempPt.Y());
  203.         }
  204.  
  205.         // add the vertex to the array
  206.         pt[numSegments + 1].x = FW_Half(rect.left + rect.right);
  207.         pt[numSegments + 1].y = FW_Half(rect.top + rect.bottom);
  208.  
  209.         ODRgnHandle hPolygonRgn = ::FW_CreatePolygonRegion(numSegments + 2, pt);
  210.         
  211.         if(hPolygonRgn != NULL)
  212.         {
  213.             ODRgnHandle hEllipticRgn = FW_CreateOvalRegion(rect);
  214.             
  215.             #ifdef FW_BUILD_MAC
  216.                 ::SectRgn(hEllipticRgn, hPolygonRgn, hArcRegion);
  217.                 
  218.                 if(::QDError() != noErr)
  219.                 {
  220.                     FW_DisposeRegion(hArcRegion);
  221.                     hArcRegion = NULL;
  222.                 }
  223.                 
  224.             #endif
  225.             #ifdef FW_BUILD_WIN
  226.                 ::CombineRgn(hArcRegion, hEllipticRgn, hPolygonRgn, RGN_AND);
  227.             #endif
  228.  
  229.             FW_DisposeRegion(hEllipticRgn);
  230.         }
  231.         
  232.         FW_DisposeRegion(hPolygonRgn);
  233.     }
  234.     
  235.     // Return the result
  236.     return hArcRegion;
  237. }
  238.  
  239.  
  240. #ifdef FW_BUILD_MAC
  241.  
  242. //----------------------------------------------------------------------------------------
  243. //    FW_PrivMacDrawPolyPoints
  244. //----------------------------------------------------------------------------------------
  245.  
  246. inline void FW_PrivMacDrawPolyPoints(unsigned long pointCount, const FW_SPoint* pointArray, Boolean closed)
  247. {
  248.     FW_CPlatformPoint startPt = pointArray[0];
  249.     FW_CPlatformPoint lastPt = startPt;
  250.     FW_CPlatformPoint pt;
  251.  
  252.     ::MoveTo(startPt.h, startPt.v);
  253.     
  254.     for(unsigned long i = 1; i < pointCount; i ++)
  255.     {
  256.         pt = pointArray[i];
  257.         if(pt != lastPt)
  258.         {
  259.             lastPt = pt;
  260.             ::LineTo(pt.h, pt.v);
  261.         }
  262.     }
  263.     
  264.     if(closed && (startPt != pt))
  265.         ::LineTo(startPt.h, startPt.v);
  266. }
  267.  
  268. #endif
  269.  
  270. //----------------------------------------------------------------------------------------
  271. //    FW_CreatePolygonRegion
  272. //----------------------------------------------------------------------------------------
  273.  
  274. ODRgnHandle SL_API    FW_CreatePolygonRegion(unsigned long pointCount, const FW_SPoint* pointArray)
  275. {
  276.     // No try block necessary - Do not throw
  277. #ifdef FW_BUILD_MAC
  278.     GrafPtr savePort = ::PrivMacOpenRegion();
  279.     
  280.     FW_PrivMacDrawPolyPoints(pointCount, pointArray, true);
  281.     
  282.     ODRgnHandle resultRgn = ::PrivMacCloseRegion(savePort);
  283.  
  284.     return resultRgn;
  285. #endif
  286. #ifdef FW_BUILD_WIN
  287.     FW_CPlatformPoint* points = new FW_CPlatformPoint[pointCount];
  288.     
  289.     for(unsigned long i = 0; i < pointCount; i ++)
  290.         points[i] = pointArray[i];
  291.  
  292.     HRGN hRgn = ::CreatePolygonRgn(points, pointCount, ALTERNATE);
  293.     delete[] points;
  294.     
  295.     return hRgn;
  296. #endif
  297. }
  298.  
  299. //----------------------------------------------------------------------------------------
  300. //    FW_CreateLineRegion
  301. //----------------------------------------------------------------------------------------
  302.  
  303. ODRgnHandle SL_API    FW_CreateLineRegion(const FW_SPoint& startPt,
  304.                                              const FW_SPoint& endPt,
  305.                                              const FW_SPoint& lineThickness)
  306. {
  307.     // No try block necessary - Do not throw
  308.     ODRgnHandle rgn;
  309.     
  310.     FW_CPlatformPoint firstPoint(startPt);
  311.     FW_CPlatformPoint lastPoint(endPt);
  312.     FW_CPlatformPoint penSize(lineThickness);
  313.     
  314.     FW_CPlatformRect halfPen(-penSize.X() / 2, -penSize.Y() / 2, (penSize.X() + 1) / 2, (penSize.Y() + 1) / 2);
  315.  
  316.     FW_CPlatformRect rect(firstPoint.X() + halfPen.left, firstPoint.Y() + halfPen.top, firstPoint.X() + halfPen.right, firstPoint.Y() + halfPen.bottom);
  317.  
  318.     short regionCode = 0;
  319.     if (lastPoint.X() < rect.left)
  320.         regionCode = 0x0008;
  321.     else if (lastPoint.X() > rect.right)
  322.         regionCode = 0x0004;
  323.     
  324.     if (lastPoint.Y() < rect.top)
  325.         regionCode |= 0x0001;
  326.     else if (lastPoint.Y() > rect.bottom)
  327.         regionCode |= 0x0002;
  328.  
  329.     short nbPoint;
  330.     FW_CPlatformPoint pt[6];
  331.     
  332.     switch (regionCode)
  333.     {
  334.         case 0x0000:
  335.             pt[0].Set(firstPoint.X() + halfPen.left, firstPoint.Y() + halfPen.top);
  336.             pt[1].Set(lastPoint.X() + halfPen.right, lastPoint.Y() + halfPen.bottom);
  337.             nbPoint = 2;
  338.             break;
  339.         case 0x0004:
  340.             pt[0].Set(firstPoint.X() + halfPen.left, firstPoint.Y() + halfPen.top);
  341.             pt[1].Set(lastPoint.X() + halfPen.right, lastPoint.Y() + halfPen.bottom);
  342.             nbPoint = 2;
  343.             break;
  344.         case 0x0008:
  345.             pt[0].Set(lastPoint.X() + halfPen.left, firstPoint.Y() + halfPen.top);
  346.             pt[1].Set(firstPoint.X() + halfPen.right, lastPoint.Y() + halfPen.bottom);
  347.             nbPoint = 2;
  348.             break;
  349.         case 0x0002:
  350.             pt[0].Set(firstPoint.X() + halfPen.left, firstPoint.Y() + halfPen.top);
  351.             pt[1].Set(lastPoint.X() + halfPen.right, lastPoint.Y() + halfPen.bottom);
  352.             nbPoint = 2;
  353.             break;
  354.         case 0x0001:
  355.             pt[0].Set(firstPoint.X() + halfPen.left, lastPoint.Y() + halfPen.top);
  356.             pt[1].Set(lastPoint.X() + halfPen.right, firstPoint.Y() + halfPen.bottom);
  357.             nbPoint = 2;
  358.             break;
  359.         case 0x0005:
  360.             pt[0].Set(firstPoint.X() + halfPen.left, firstPoint.Y() + halfPen.top);
  361.             pt[1].Set(firstPoint.X() + halfPen.left, firstPoint.Y() + halfPen.bottom);
  362.             pt[2].Set(firstPoint.X() + halfPen.right, firstPoint.Y() + halfPen.bottom);
  363.             pt[3].Set(lastPoint.X() + halfPen.right, lastPoint.Y() + halfPen.bottom);
  364.             pt[4].Set(lastPoint.X() + halfPen.right, lastPoint.Y() + halfPen.top);
  365.             pt[5].Set(lastPoint.X() + halfPen.left, lastPoint.Y() + halfPen.top);
  366.             nbPoint = 6;
  367.             break;
  368.         case 0x0006:
  369.             pt[0].Set(firstPoint.X() + halfPen.right, firstPoint.Y() + halfPen.top);
  370.             pt[1].Set(firstPoint.X() + halfPen.left, firstPoint.Y() + halfPen.top);
  371.             pt[2].Set(firstPoint.X() + halfPen.left, firstPoint.Y() + halfPen.bottom);
  372.             pt[3].Set(lastPoint.X() + halfPen.left, lastPoint.Y() + halfPen.bottom);
  373.             pt[4].Set(lastPoint.X() + halfPen.right, lastPoint.Y() + halfPen.bottom);
  374.             pt[5].Set(lastPoint.X() + halfPen.right, lastPoint.Y() + halfPen.top);
  375.             nbPoint = 6;
  376.             break;
  377.         case 0x000A:
  378.             pt[0].Set(firstPoint.X() + halfPen.left, firstPoint.Y() + halfPen.top);
  379.             pt[1].Set(firstPoint.X() + halfPen.right, firstPoint.Y() + halfPen.top);
  380.             pt[2].Set(firstPoint.X() + halfPen.right, firstPoint.Y() + halfPen.bottom);
  381.             pt[3].Set(lastPoint.X() + halfPen.right, lastPoint.Y() + halfPen.bottom);
  382.             pt[4].Set(lastPoint.X() + halfPen.left, lastPoint.Y() + halfPen.bottom);
  383.             pt[5].Set(lastPoint.X() + halfPen.left, lastPoint.Y() + halfPen.top);
  384.             nbPoint = 6;
  385.             break;
  386.         case 0x0009:
  387.             pt[0].Set(firstPoint.X() + halfPen.right, firstPoint.Y() + halfPen.top);
  388.             pt[1].Set(firstPoint.X() + halfPen.right, firstPoint.Y() + halfPen.bottom);
  389.             pt[2].Set(firstPoint.X() + halfPen.left, firstPoint.Y() + halfPen.bottom);
  390.             pt[3].Set(lastPoint.X() + halfPen.left, lastPoint.Y() + halfPen.bottom);
  391.             pt[4].Set(lastPoint.X() + halfPen.left, lastPoint.Y() + halfPen.top);
  392.             pt[5].Set(lastPoint.X() + halfPen.right, lastPoint.Y() + halfPen.top);
  393.             nbPoint = 6;
  394.             break;
  395.     }
  396.     
  397. #ifdef FW_BUILD_WIN
  398.     if (nbPoint == 2)
  399.         rgn = ::CreateRectRgn(pt[0].x, pt[0].y, pt[1].x, pt[1].y);
  400.     else
  401.         rgn = ::CreatePolygonRgn(pt, nbPoint, WINDING);
  402. #endif        
  403.     
  404. #ifdef FW_BUILD_MAC
  405.     if (nbPoint == 2)
  406.     {
  407.         rgn = ::FW_NewRegion();
  408.         FW_CPlatformRect rect(pt[0], pt[1]);
  409.         ::RectRgn(rgn, &rect);
  410.     }
  411.     else
  412.     {
  413.         GrafPtr svPort = ::PrivMacOpenRegion();
  414.         ::MoveTo(pt[0].h, pt[0].v);
  415.         ::LineTo(pt[1].h, pt[1].v);
  416.         ::LineTo(pt[2].h, pt[2].v);            
  417.         ::LineTo(pt[3].h, pt[3].v);
  418.         ::LineTo(pt[4].h, pt[4].v);            
  419.         ::LineTo(pt[5].h, pt[5].v);
  420.         ::LineTo(pt[0].h, pt[0].v);
  421.         rgn = ::PrivMacCloseRegion(svPort);
  422.     }
  423. #endif
  424.  
  425.     return rgn;
  426. }
  427.  
  428. //----------------------------------------------------------------------------------------
  429. //    FW_CopyRegion
  430. //----------------------------------------------------------------------------------------
  431.  
  432. ODRgnHandle SL_API    FW_CopyRegion(ODRgnHandle scrRgn)
  433. {
  434.     // No try block necessary - Do not throw
  435.     FW_ASSERT(scrRgn != NULL);
  436.     
  437.     ODRgnHandle newRgn = ::FW_NewRegion();
  438.  
  439. #ifdef FW_BUILD_MAC
  440.     ::CopyRgn(scrRgn, newRgn);
  441. #endif
  442. #ifdef FW_BUILD_WIN
  443.     ::CombineRgn(newRgn, scrRgn, NULL, RGN_COPY);
  444. #endif
  445.  
  446.     return newRgn;
  447. }
  448.  
  449. //----------------------------------------------------------------------------------------
  450. //    FW_CopyRegionTo
  451. //----------------------------------------------------------------------------------------
  452.  
  453. void SL_API    FW_CopyRegionTo(ODRgnHandle scrRgn, ODRgnHandle dstRgn)
  454. {
  455.     // No try block necessary - Do not throw
  456.     FW_ASSERT(scrRgn != NULL);
  457.     FW_ASSERT(dstRgn != NULL);
  458.     
  459. #ifdef FW_BUILD_MAC
  460.     ::CopyRgn(scrRgn, dstRgn);
  461. #endif
  462. #ifdef FW_BUILD_WIN
  463.     ::CombineRgn(dstRgn, scrRgn, NULL, RGN_COPY);
  464. #endif
  465. }
  466.  
  467. //----------------------------------------------------------------------------------------
  468. //    FW_NewRegion
  469. //----------------------------------------------------------------------------------------
  470.  
  471. ODRgnHandle SL_API    FW_NewRegion()
  472. {    
  473.     // No try block necessary - Do not throw
  474. #ifdef FW_BUILD_MAC
  475.     ODRgnHandle r;
  476.     FW_TRY
  477.     {
  478.         r = (ODRgnHandle)FW_CMemoryManager::AllocateSystemHandle(sizeof(Region));
  479.     }
  480.     FW_CATCH_BEGIN
  481.     FW_CATCH_EVERYTHING()
  482.     {
  483.         return NULL;
  484.     }
  485.     FW_CATCH_END
  486.     (**r).rgnSize = sizeof(Region);
  487.     SetRect(&(**r).rgnBBox, 0,0,0,0);
  488.     return r;
  489. #endif
  490.  
  491. #ifdef FW_BUILD_WIN
  492.     return ::CreateRectRgn(0,0,0,0);
  493. #endif
  494. }
  495.  
  496. //----------------------------------------------------------------------------------------
  497. //    FW_DisposeRegion
  498. //----------------------------------------------------------------------------------------
  499.  
  500. void SL_API    FW_DisposeRegion(ODRgnHandle rgn)
  501. {
  502.     // No try block necessary - Do not throw
  503.     FW_ASSERT(rgn != 0);
  504.     
  505. #ifdef FW_BUILD_MAC
  506.     FW_CMemoryManager::FreeSystemHandle((FW_PlatformHandle)rgn);
  507. #endif
  508. #ifdef FW_BUILD_WIN
  509.     ::DeleteObject(rgn);
  510. #endif
  511. }
  512.  
  513. //----------------------------------------------------------------------------------------
  514. //    FW_OutlineRegion
  515. //----------------------------------------------------------------------------------------
  516.  
  517. void SL_API    FW_OutlineRegion(ODRgnHandle rgn, FW_Fixed outlineSize)
  518. {
  519.     ODRgnHandle tempRgn = ::FW_CopyRegion(rgn);
  520.     
  521.     if (outlineSize <= FW_kFixed0)
  522.         outlineSize = FW_kFixedPos1;
  523.     
  524.     ::FW_InsetRegion(tempRgn, outlineSize, outlineSize);
  525.     
  526. #ifdef FW_BUILD_MAC
  527.     ::DiffRgn(rgn, tempRgn, rgn);
  528. #endif
  529. #ifdef FW_BUILD_WIN
  530.     ::CombineRgn(rgn, rgn, tempRgn, RGN_DIFF);
  531. #endif
  532.  
  533.     ::FW_DisposeRegion(tempRgn);
  534. }
  535.  
  536. //----------------------------------------------------------------------------------------
  537. //    FW_InsetRegion
  538. //----------------------------------------------------------------------------------------
  539.  
  540. void SL_API    FW_InsetRegion(ODRgnHandle rgn, FW_Fixed x, FW_Fixed y)
  541. {
  542.     // No try block necessary - Do not throw
  543. #ifdef FW_BUILD_MAC
  544.     ::InsetRgn(rgn, FW_FixedToInt(x), FW_FixedToInt(y));
  545. #endif
  546. #ifdef FW_BUILD_WIN
  547.     int dx = FW_FixedToInt(x);
  548.     int dy = FW_FixedToInt(y);
  549.     
  550.     if (dx == 0 && dy == 0)
  551.         return;
  552.  
  553.     // Note: This code relies on partially documented Windows GDI data structures!
  554.  
  555.     // Get the current region data
  556.     long size = ::GetRegionData(rgn, 0, NULL);
  557.     
  558.     FW_CAcquireTemporaryMemory tempMem(size);
  559.     LPRGNDATA rgnData = (LPRGNDATA) tempMem.GetPointer();
  560.     ::GetRegionData(rgn, size, rgnData);
  561.     
  562.     // Massage the region data
  563.     if(rgnData->rdh.iType == RDH_RECTANGLES)
  564.     {
  565.         POINT ptCenter;
  566.         ptCenter.x = (rgnData->rdh.rcBound.left + rgnData->rdh.rcBound.right) / 2;
  567.         ptCenter.y = (rgnData->rdh.rcBound.top  + rgnData->rdh.rcBound.bottom) / 2;
  568.         
  569.         LPRECT lpRect = (LPRECT) rgnData->Buffer;
  570.  
  571.         for(unsigned long i = 0; i < rgnData->rdh.nCount; ++ i, ++ lpRect)
  572.             ::PrivWinInsetRegionRectangle(lpRect, dx, dy, ptCenter);
  573.     }
  574.  
  575.     // Create a new region and replace the one passed in    
  576.     HRGN hNewRgn = ::ExtCreateRegion(NULL, size, rgnData);
  577.     if(hNewRgn == NULL)
  578.         FW_Failure(FW_xMemoryExhausted);
  579.  
  580.     ::FW_CopyRegionTo(hNewRgn, rgn);
  581.     ::FW_DisposeRegion(hNewRgn);
  582. #endif
  583. }
  584.  
  585. //----------------------------------------------------------------------------------------
  586. //    FW_MapRegion
  587. //----------------------------------------------------------------------------------------
  588.  
  589. void SL_API    FW_MapRegion(ODRgnHandle rgn, const FW_SRect& srcRect, const FW_SRect& dstRect)
  590. {
  591.     // No try block necessary - Do not throw
  592.     FW_CPlatformRect plfmSrc(srcRect);
  593.     FW_CPlatformRect plfmDst(dstRect);
  594.     
  595. #ifdef FW_BUILD_MAC
  596.     ::MapRgn(rgn, &plfmSrc, &plfmDst);
  597. #endif
  598. #ifdef FW_BUILD_WIN
  599.     // Get the current region data
  600.     long size = ::GetRegionData(rgn, 0, NULL);
  601.     
  602.     FW_CAcquireTemporaryMemory tempMem(size);
  603.     LPRGNDATA rgnData = (LPRGNDATA) tempMem.GetPointer();
  604.     ::GetRegionData(rgn, size, rgnData);
  605.  
  606.     // Figure out the desired transform
  607.     XFORM xform;
  608.     xform.eM11 = (float) FW_FixedToDouble((dstRect.right - dstRect.left) / (srcRect.right - srcRect.left));
  609.     xform.eM12 = 0.0f;
  610.     xform.eM21 = 0.0f;
  611.     xform.eM22 = (float) FW_FixedToDouble((dstRect.bottom - dstRect.top) / (srcRect.bottom - srcRect.top));
  612.     xform.eDx  = (float) FW_FixedToDouble(dstRect.left - srcRect.left);
  613.     xform.eDy  = (float) FW_FixedToDouble(dstRect.top  - srcRect.top);
  614.  
  615.     // Create a new region and replace the one passed in    
  616.     HRGN hNewRgn = ::ExtCreateRegion(&xform, size, rgnData);
  617.     if(hNewRgn == NULL)
  618.         FW_Failure(FW_xMemoryExhausted);
  619.  
  620.     ::FW_CopyRegionTo(hNewRgn, rgn);
  621.     ::FW_DisposeRegion(hNewRgn);
  622. #endif
  623. }
  624.  
  625. //----------------------------------------------------------------------------------------
  626. //    FW_EmptyRegion
  627. //----------------------------------------------------------------------------------------
  628.  
  629. void SL_API    FW_EmptyRegion(ODRgnHandle rgn)
  630. {
  631.     // No try block necessary - Do not throw
  632. #ifdef FW_BUILD_MAC
  633.     ::SetEmptyRgn(rgn);
  634. #endif
  635. #ifdef FW_BUILD_WIN
  636.     ::SetRectRgn(rgn, 0, 0, 0, 0);
  637. #endif
  638. }
  639.  
  640. //----------------------------------------------------------------------------------------
  641. //    FW_OffsetRegion
  642. //----------------------------------------------------------------------------------------
  643.  
  644. void SL_API    FW_OffsetRegion(ODRgnHandle rgn, FW_Fixed x, FW_Fixed y)
  645. {
  646.     ::OffsetRgn(rgn, FW_FixedToInt(x), FW_FixedToInt(y));
  647. }
  648.  
  649. //----------------------------------------------------------------------------------------
  650. //    FW_GetRegionBoundingBox
  651. //----------------------------------------------------------------------------------------
  652.  
  653. void SL_API    FW_GetRegionBoundingBox(ODRgnHandle rgn, FW_SRect& rect)
  654. {
  655.     // No try block necessary - Do not throw
  656. #ifdef FW_BUILD_MAC
  657.     rect = FW_CRect((*rgn)->rgnBBox);
  658. #endif
  659. #ifdef FW_BUILD_WIN
  660.     FW_CPlatformRect plfmRect;
  661.     ::GetRgnBox(rgn, &plfmRect);
  662.     rect = FW_CRect(plfmRect);
  663. #endif
  664. }
  665.  
  666. //----------------------------------------------------------------------------------------
  667. //    FW_PointInRegion
  668. //----------------------------------------------------------------------------------------
  669.  
  670. FW_Boolean SL_API    FW_PointInRegion(ODRgnHandle rgn, const FW_SPoint& point)
  671. {
  672.     // No try block necessary - Do not throw
  673.     FW_CPlatformPoint plfmPt = point;
  674. #ifdef FW_BUILD_MAC
  675.     return ::PtInRgn(plfmPt, rgn);
  676. #endif
  677. #ifdef FW_BUILD_WIN
  678.     return ::PtInRegion(rgn, plfmPt.X(), plfmPt.Y());
  679. #endif
  680. }
  681.  
  682. //----------------------------------------------------------------------------------------
  683. //    FW_RectInRegion
  684. //----------------------------------------------------------------------------------------
  685.  
  686. FW_Boolean SL_API    FW_RectInRegion(ODRgnHandle rgn, const FW_SRect& rect)
  687. {
  688.     // No try block necessary - Do not throw
  689.     FW_CPlatformRect plfmRect = rect;
  690. #ifdef FW_BUILD_MAC
  691.     return ::RectInRgn(&plfmRect, rgn);
  692. #endif
  693. #ifdef FW_BUILD_WIN
  694.     return ::RectInRegion(rgn, &plfmRect);
  695. #endif
  696. }
  697.  
  698. //----------------------------------------------------------------------------------------
  699. //    FW_IsEmptyRegion
  700. //----------------------------------------------------------------------------------------
  701.  
  702. FW_Boolean SL_API    FW_IsEmptyRegion(ODRgnHandle rgn)
  703. {
  704.     // No try block necessary - Do not throw
  705. #ifdef FW_BUILD_MAC
  706.     return ::EmptyRgn(rgn);
  707. #endif
  708. #ifdef FW_BUILD_WIN
  709.     return ::CombineRgn(rgn, rgn, rgn, RGN_AND) == NULLREGION;
  710. #endif
  711. }
  712.  
  713. #ifdef FW_BUILD_MAC
  714. //----------------------------------------------------------------------------------------
  715. //    PrivMacOpenRegion
  716. //----------------------------------------------------------------------------------------
  717.  
  718. static GrafPtr PrivMacOpenRegion()
  719. {
  720.     GrafPtr svPort;
  721.     ::GetPort(&svPort);
  722.     ::SetPort(FW_gScratchPort);
  723.     ::OpenRgn();
  724.     return svPort;
  725. }
  726. #endif
  727.  
  728. #ifdef FW_BUILD_MAC
  729. //----------------------------------------------------------------------------------------
  730. //    PrivMacCloseRegion
  731. //----------------------------------------------------------------------------------------
  732.  
  733. ODRgnHandle PrivMacCloseRegion(GrafPtr svPort)
  734. {
  735.     ODRgnHandle hRgn = ::FW_NewRegion();
  736.     ::CloseRgn(hRgn);
  737.     OSErr err = ::QDError();
  738.     if(err != noErr)
  739.     {
  740.         ::FW_DisposeRegion(hRgn);
  741.         hRgn = NULL;
  742.     }
  743.     ::SetPort(svPort);
  744.     return hRgn;
  745. }
  746. #endif
  747.  
  748. #ifdef FW_BUILD_WIN
  749.  
  750. //----------------------------------------------------------------------------------------
  751. //    PrivWinInsetRegionPoint
  752. //----------------------------------------------------------------------------------------
  753.  
  754. static void PrivWinInsetRegionRectangle(LPPOINT lppt, int dx, int dy, const POINT& ptCenter)
  755. {
  756.     if (lppt->x < ptCenter.x)
  757.     {
  758.         if ((lppt->x += dx) > ptCenter.x)
  759.             lppt->x = ptCenter.x;
  760.     }
  761.     else
  762.     {
  763.         if ((lppt->x -= dx) < ptCenter.x)
  764.             lppt->x = ptCenter.x;
  765.     }
  766.  
  767.     if (lppt->y < ptCenter.y)
  768.     {
  769.         if((lppt->y += dy) > ptCenter.y)
  770.             lppt->y = ptCenter.y;
  771.     }
  772.     else
  773.     {
  774.         if ((lppt->y -= dy) < ptCenter.y)
  775.             lppt->y = ptCenter.y;
  776.     }
  777. }
  778.  
  779. //----------------------------------------------------------------------------------------
  780. //    PrivWinInsetRegionRectangle
  781. //----------------------------------------------------------------------------------------
  782.  
  783. static void PrivWinInsetRegionRectangle(LPRECT lpRect, int dx, int dy, const POINT& ptCenter)
  784. {
  785.     PrivWinInsetRegionRectangle(((LPPOINT) lpRect) + 0, dx, dy, ptCenter);
  786.     PrivWinInsetRegionRectangle(((LPPOINT) lpRect) + 1, dx, dy, ptCenter);
  787. }
  788.  
  789. #endif
  790.  
  791. //----------------------------------------------------------------------------------------
  792. //    FW_WriteRegion
  793. //----------------------------------------------------------------------------------------
  794.  
  795. void SL_API FW_WriteRegion(ODRgnHandle rgnHandle, FW_HWritableStream hStream, FW_PlatformError* error)
  796. {
  797.     FW_ERR_TRY
  798.     {
  799.         FW_CWritableStream stream(hStream);
  800.     
  801. #ifdef FW_BUILD_WIN
  802.         long size = ::GetRegionData(rgnHandle, 0, NULL);
  803.         
  804.         FW_CAcquireTemporaryMemory tempMem(size);
  805.         LPRGNDATA rgnData = (LPRGNDATA) tempMem.GetPointer();
  806.         ::GetRegionData(rgnHandle, size, rgnData);
  807.         
  808.         stream << size;
  809.         stream.Write(rgnData, size);
  810. #endif
  811. #ifdef FW_BUILD_MAC
  812.         short size = (*rgnHandle)->rgnSize;
  813.         
  814.         FW_CAcquireLockedSystemHandle memHandle((FW_PlatformHandle)rgnHandle);
  815.         void* rgnData = memHandle.GetPointer();
  816.         
  817.         stream << size;
  818.         stream.Write(rgnData, size);
  819. #endif
  820.     }
  821.     FW_ERR_CATCH
  822. }
  823.  
  824. //----------------------------------------------------------------------------------------
  825. //    FW_ReadRegion
  826. //----------------------------------------------------------------------------------------
  827.  
  828. ODRgnHandle SL_API FW_ReadRegion(FW_HReadableStream hStream, FW_PlatformError* error)
  829. {
  830.     FW_ERR_TRY
  831.     {
  832.         FW_CReadableStream stream(hStream);
  833.     
  834. #ifdef FW_BUILD_WIN
  835.         long size;
  836.         stream >> size;
  837.         
  838.         FW_CAcquireTemporaryMemory tempMem(size);
  839.         LPRGNDATA rgnData = (LPRGNDATA) tempMem.GetPointer();
  840.         stream.Read(rgnData, size);
  841.     
  842.         return ::ExtCreateRegion(NULL, size, rgnData);
  843. #endif
  844. #ifdef FW_BUILD_MAC
  845.         short size;
  846.         stream >> size;
  847.         
  848.         FW_CAcquireTemporarySystemHandle memHandle(size);
  849.         void* rgnData = memHandle.GetPointer();
  850.         
  851.         stream.Read(rgnData, size);
  852.     
  853.         memHandle.Orphan();
  854.         return (ODRgnHandle) memHandle.GetPlatformHandle();
  855. #endif
  856.     }
  857.     FW_ERR_CATCH
  858.     return NULL;
  859. }
  860.  
  861. //----------------------------------------------------------------------------------------
  862. //    FW_UnionRegion
  863. //----------------------------------------------------------------------------------------
  864.  
  865. ODRgnHandle SL_API FW_UnionRegion(ODRgnHandle rgn1, ODRgnHandle rgn2)
  866. {
  867.     // No try block necessary - Do not throw
  868.     ODRgnHandle dstRgn = ::FW_NewRegion();
  869.     if (dstRgn == NULL)
  870.         return NULL;
  871.     
  872. #ifdef FW_BUILD_MAC
  873.     ::UnionRgn(rgn1, rgn2, dstRgn);
  874. #endif
  875. #ifdef FW_BUILD_WIN
  876.     ::CombineRgn(dstRgn, rgn1, rgn2, RGN_OR);
  877. #endif
  878.  
  879.     return dstRgn;
  880. }
  881.  
  882. //----------------------------------------------------------------------------------------
  883. //    FW_XorRegion
  884. //----------------------------------------------------------------------------------------
  885.  
  886. ODRgnHandle SL_API FW_XorRegion(ODRgnHandle rgn1, ODRgnHandle rgn2)
  887. {
  888.     // No try block necessary - Do not throw
  889.     ODRgnHandle dstRgn = ::FW_NewRegion();
  890.     if (dstRgn == NULL)
  891.         return NULL;
  892.         
  893. #ifdef FW_BUILD_MAC
  894.     ::XorRgn(rgn1, rgn2, dstRgn);
  895. #endif
  896. #ifdef FW_BUILD_WIN
  897.     ::CombineRgn(dstRgn, rgn1, rgn2, RGN_XOR);
  898. #endif
  899.  
  900.     return dstRgn;
  901. }
  902.  
  903. //----------------------------------------------------------------------------------------
  904. //    FW_SubtractRegion
  905. //----------------------------------------------------------------------------------------
  906.  
  907. ODRgnHandle SL_API FW_SubtractRegion(ODRgnHandle rgn1, ODRgnHandle rgn2)
  908. {
  909.     // No try block necessary - Do not throw
  910.     ODRgnHandle dstRgn = ::FW_NewRegion();
  911.     if (dstRgn == NULL)
  912.         return NULL;
  913.     
  914. #ifdef FW_BUILD_MAC
  915.     ::DiffRgn(rgn1, rgn2, dstRgn);
  916. #endif
  917. #ifdef FW_BUILD_WIN
  918.     ::CombineRgn(dstRgn, rgn1, rgn2, RGN_DIFF);
  919. #endif
  920.  
  921.     return dstRgn;
  922. }
  923.  
  924. //----------------------------------------------------------------------------------------
  925. //    FW_IntersectRegion
  926. //----------------------------------------------------------------------------------------
  927.  
  928. ODRgnHandle SL_API FW_IntersectRegion(ODRgnHandle rgn1, ODRgnHandle rgn2)
  929. {
  930.     // No try block necessary - Do not throw
  931.     ODRgnHandle dstRgn = ::FW_NewRegion();
  932.     if (dstRgn == NULL)
  933.         return NULL;
  934.     
  935. #ifdef FW_BUILD_MAC
  936.     ::SectRgn(rgn1, rgn2, dstRgn);
  937. #endif
  938. #ifdef FW_BUILD_WIN
  939.     ::CombineRgn(dstRgn, rgn1, rgn2, RGN_AND);
  940. #endif
  941.  
  942.     return dstRgn;
  943. }
  944.  
  945.